#include <btl/Image/PixelTypes.hpp>
#include <btl/Image/Image.hpp>
#include <btl/Image/ColourConversion.hpp>

#include <boost/test/unit_test.hpp>
#include <iosfwd>
#include <iostream>
#include <cstddef>

namespace btl
{
namespace image
{
std::ostream& operator<<(std::ostream& ss, const PixelRGB& p)
{
   return (ss << "PixelRGB(" << (int)p.red() << "," << (int)p.green() << "," << (int)p.blue() << ")");
}
}
}

BOOST_AUTO_TEST_SUITE(Image_ColourConversion)

BOOST_AUTO_TEST_CASE(conversion_grey_rgb)
{
   using namespace btl::image;

   for(int i = 0; i < 256; ++i)
   {
      PixelConverter<PixelGrey, PixelRGB> cvt;
      BOOST_CHECK_EQUAL(i, cvt(PixelRGB(i)));
   }

   for(int i = 0; i < 256; ++i)
   {
      PixelConverter<PixelRGB, PixelGrey> cvt;
      BOOST_CHECK_EQUAL(PixelRGB(i), cvt(i));
   }
}

BOOST_AUTO_TEST_CASE(conversion_grey_float)
{
   using namespace btl::image;

   // check that grey -> float is correctly invertible
   for(int i = 0; i < 256; ++i)
   {
      PixelConverter<PixelGrey, PixelFloat> ftog;
      PixelConverter<PixelFloat, PixelGrey> gtof;

      BOOST_CHECK_EQUAL(i, (int)ftog(gtof(i)));
   }

   {
      PixelConverter<PixelGrey, PixelFloat> cvt;
      BOOST_CHECK_EQUAL(0, cvt(0.0f));
      BOOST_CHECK_EQUAL(127, cvt(0.5f));
      BOOST_CHECK_EQUAL(255, cvt(1.0f));
   }

   {
      PixelConverter<PixelFloat, PixelGrey> cvt;
      BOOST_CHECK_EQUAL(0.0, cvt(0));
      BOOST_CHECK_EQUAL(127.0f / 255.0f, cvt(127));
      BOOST_CHECK_EQUAL(1.0, cvt(255));
   }
}

BOOST_AUTO_TEST_CASE(conversion_identity)
{
   using namespace btl::image;

   for(int i = 0; i < 256; ++i)
   {
      PixelConverter<PixelFloat, PixelGrey> gtof;
      const PixelGrey g = i;
      const PixelFloat f = gtof(i);

      PixelGrey g2 = convert_pixel<PixelGrey>(g);
      BOOST_CHECK_EQUAL(g, g2);

      PixelFloat f2 = convert_pixel<PixelFloat>(f);
      BOOST_CHECK_EQUAL(f, f2);
   }

   const int w = 320;
   const int h = 240;

   Image<PixelGrey> im1;
   Image<PixelGrey> im2;

   im1.allocate(w, h);
   im2.allocate(w, h, PixelGrey(0));

   for(int i = 0; i < h; ++i)
   {
      for(int j = 0; j < w; ++j)
      {
         im1(i, j) = PixelGrey(i + j);
         BOOST_CHECK_EQUAL(0, im2(i, j));
      }
   }

   convert_image(im2, im1);

   for(int i = 0; i < h; ++i)
      for(int j = 0; j < w; ++j)
         BOOST_CHECK_EQUAL(im1(i, j), im2(i, j));
}

BOOST_AUTO_TEST_CASE(image_conversion)
{
   using namespace btl::image;

   Image<PixelRGB> imrgb;
   Image<PixelGrey> imgrey;

   const int w = 320;
   const int h = 240;

   imrgb.allocate(w, h);
   imgrey.allocate(w, h);

   for(int i = 0; i < h; ++i)
      for(int j = 0; j < w; ++j)
         imrgb(i, j) = PixelRGB(i, i, i);

   convert_image(imgrey, imrgb);

   for(int i = 0; i < h; ++i)
      for(int j = 0; j < w; ++j)
         BOOST_CHECK_EQUAL(i, imgrey(i, j));
}

BOOST_AUTO_TEST_SUITE_END()
